Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Displaying Raw • Download


meshchatx/src/frontend/components/map/MiniChat.vue ec74a2651e897325b14269ae52d11b1e12f0b6e2 (ec74a265) Text, 8.01 KB

T8b949e<!-- SPDX-License-Identifier: 0BSD -->

Tb4b4b4<Tff7b72templateTb4b4b4>
Tb4b4b4<Tff7b72div
Te6edf3classTff7b72=Ta5d6ff"flex flex-col h-64 bg-gray-50 dark:bg-zinc-950 rounded-lg overflow-hidden border border-gray-200 dark:border-zinc-800"
Tb4b4b4>
T8b949e<!-- message list -->
Tb4b4b4<Tff7b72div Te6edf3refTff7b72=Ta5d6ff"messageList" Te6edf3classTff7b72=Ta5d6ff"flex-1 overflow-y-auto p-2 space-y-2 scrollbar-thin"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3v-ifTff7b72=Ta5d6ff"Te6edf3loadingTa5d6ff" Te6edf3classTff7b72=Ta5d6ff"flex justify-center py-4"Tb4b4b4>
Tb4b4b4<Tff7b72v-icon Te6edf3iconTff7b72=Ta5d6ff"mdi-loading" Te6edf3classTff7b72=Ta5d6ff"animate-spin text-gray-400" Te6edf3sizeTff7b72=Ta5d6ff"20"Tb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72v-iconTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3v-else-ifTff7b72=Ta5d6ff"Te6edf3messagesTb4b4b4.Te6edf3length Tff7b72=== T79c0ff0Ta5d6ff" Te6edf3classTff7b72=Ta5d6ff"text-center py-4 text-xs text-gray-400"Tb4b4b4>No messages yetTb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div
Te6edf3v-forTff7b72=Ta5d6ff"Te6edf3msg Tff7b72in Te6edf3messagesTa5d6ff"
Tb4b4b4:Te6edf3keyTff7b72=Ta5d6ff"Te6edf3msgTb4b4b4.Te6edf3hashTa5d6ff"
Te6edf3classTff7b72=Ta5d6ff"flex flex-col max-w-[90%]"
Tb4b4b4:Te6edf3classTff7b72=Ta5d6ff"Te6edf3msgTb4b4b4.Te6edf3is_outbound Tff7b72? Ta5d6ff'ml-auto items-end' Tff7b72: Ta5d6ff'mr-auto items-start'Ta5d6ff"
Tb4b4b4>
Tb4b4b4<Tff7b72div
Te6edf3classTff7b72=Ta5d6ff"px-2 py-1 rounded-lg text-xs wrap-break-word shadow-xs"
Tb4b4b4:Te6edf3classTff7b72=Ta5d6ff"
Te6edf3msgTb4b4b4.Te6edf3is_outbound
Tff7b72? Ta5d6ff'bg-blue-600 text-white'
Tff7b72: Ta5d6ff'bg-white dark:bg-zinc-900 text-gray-800 dark:text-zinc-200'
Ta5d6ff"
Tb4b4b4>
T8b949e<!-- Telemetry Header if no content -->
Tb4b4b4<Tff7b72div
Te6edf3v-ifTff7b72=Ta5d6ff"Tff7b72!Te6edf3msgTb4b4b4.Te6edf3content Tff7b72&& Te6edf3msgTb4b4b4.Te6edf3fieldsTff7b72?Tb4b4b4.Te6edf3telemetryTa5d6ff"
Te6edf3classTff7b72=Ta5d6ff"flex items-center gap-1 mb-1 pb-1 border-b border-white/10 opacity-80"
Tb4b4b4>
Tb4b4b4<Tff7b72v-icon Te6edf3iconTff7b72=Ta5d6ff"mdi-satellite-variant" Te6edf3sizeTff7b72=Ta5d6ff"10"Tb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72v-iconTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"text-[8px] font-bold uppercase tracking-wider"
Tb4b4b4>Tff7b72{{ Te6edf3msgTb4b4b4.Te6edf3is_outbound Tff7b72? Ta5d6ff"Sent" Tff7b72: Ta5d6ff"Received" Tff7b72}} TelemetryTb4b4b4<Tb4b4b4/Tff7b72span
Tb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

Tb4b4b4<Tff7b72div
Te6edf3v-ifTff7b72=Ta5d6ff"Tff7b72!Te6edf3msgTb4b4b4.Te6edf3content Tff7b72&& Te6edf3msgTb4b4b4.Te6edf3fieldsTff7b72?Tb4b4b4.Te6edf3commandsTff7b72?Tb4b4b4.Te6edf3someTb4b4b4(Tb4b4b4(Te6edf3cTb4b4b4) Tb4b4b4=> Te6edf3cTb4b4b4[Ta5d6ff'0x01'Tb4b4b4] Tff7b72|| Te6edf3cTb4b4b4[Ta5d6ff'1'Tb4b4b4] Tff7b72|| Te6edf3cTb4b4b4[Ta5d6ff'0x1'Tb4b4b4]Tb4b4b4)Ta5d6ff"
Te6edf3classTff7b72=Ta5d6ff"flex items-center gap-1 mb-1 pb-1 border-b border-white/10 opacity-80"
Tb4b4b4>
Tb4b4b4<Tff7b72v-icon Te6edf3iconTff7b72=Ta5d6ff"mdi-crosshairs-question" Te6edf3sizeTff7b72=Ta5d6ff"10"Tb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72v-iconTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3classTff7b72=Ta5d6ff"text-[8px] font-bold uppercase tracking-wider"Tb4b4b4>Location RequestTb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

Tb4b4b4<Tff7b72div Te6edf3v-ifTff7b72=Ta5d6ff"Te6edf3msgTb4b4b4.Te6edf3contentTa5d6ff" Te6edf3classTff7b72=Ta5d6ff"leading-normal"Tb4b4b4>Tff7b72{{ Te6edf3msgTb4b4b4.Te6edf3content Tff7b72}}Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

T8b949e<!-- Mini Telemetry Data -->
Tb4b4b4<Tff7b72div Te6edf3v-ifTff7b72=Ta5d6ff"Te6edf3msgTb4b4b4.Te6edf3fieldsTff7b72?Tb4b4b4.Te6edf3telemetryTa5d6ff" Te6edf3classTff7b72=Ta5d6ff"mt-1 space-y-1"Tb4b4b4>
Tb4b4b4<Tff7b72div
Te6edf3v-ifTff7b72=Ta5d6ff"Te6edf3msgTb4b4b4.Te6edf3fieldsTb4b4b4.Te6edf3telemetryTb4b4b4.Te6edf3locationTa5d6ff"
Te6edf3classTff7b72=Ta5d6ff"flex items-center gap-1 text-[9px] font-mono opacity-90"
Tb4b4b4>
Tb4b4b4<Tff7b72v-icon Te6edf3iconTff7b72=Ta5d6ff"mdi-map-marker" Te6edf3sizeTff7b72=Ta5d6ff"10"Tb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72v-iconTb4b4b4>
Tb4b4b4<Tff7b72span
Tb4b4b4>Tff7b72{{ Te6edf3msgTb4b4b4.Te6edf3fieldsTb4b4b4.Te6edf3telemetryTb4b4b4.Te6edf3locationTb4b4b4.Te6edf3latitudeTb4b4b4.Te6edf3toFixedTb4b4b4(T79c0ff4Tb4b4b4) Tff7b72}},
Tff7b72{{ Te6edf3msgTb4b4b4.Te6edf3fieldsTb4b4b4.Te6edf3telemetryTb4b4b4.Te6edf3locationTb4b4b4.Te6edf3longitudeTb4b4b4.Te6edf3toFixedTb4b4b4(T79c0ff4Tb4b4b4) Tff7b72}}Tb4b4b4<Tb4b4b4/Tff7b72span
Tb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"flex gap-2 opacity-70 text-[8px]"Tb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3v-ifTff7b72=Ta5d6ff"Te6edf3msgTb4b4b4.Te6edf3fieldsTb4b4b4.Te6edf3telemetryTb4b4b4.Te6edf3batteryTa5d6ff" Te6edf3classTff7b72=Ta5d6ff"flex items-center gap-0.5"Tb4b4b4>
Tb4b4b4<Tff7b72v-icon Te6edf3iconTff7b72=Ta5d6ff"mdi-battery" Te6edf3sizeTff7b72=Ta5d6ff"8"Tb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72v-icon
Tb4b4b4>Tff7b72{{ Te6edf3msgTb4b4b4.Te6edf3fieldsTb4b4b4.Te6edf3telemetryTb4b4b4.Te6edf3batteryTb4b4b4.Te6edf3charge_percent Tff7b72}}%
Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tff7b72span Te6edf3v-ifTff7b72=Ta5d6ff"Te6edf3msgTb4b4b4.Te6edf3fieldsTb4b4b4.Te6edf3telemetryTb4b4b4.Te6edf3physical_linkTa5d6ff" Te6edf3classTff7b72=Ta5d6ff"flex items-center gap-0.5"Tb4b4b4>
Tb4b4b4<Tff7b72v-icon Te6edf3iconTff7b72=Ta5d6ff"mdi-antenna" Te6edf3sizeTff7b72=Ta5d6ff"8"Tb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72v-iconTb4b4b4>SNR:
Tff7b72{{ Te6edf3msgTb4b4b4.Te6edf3fieldsTb4b4b4.Te6edf3telemetryTb4b4b4.Te6edf3physical_linkTb4b4b4.Te6edf3snr Tff7b72}}dB
Tb4b4b4<Tb4b4b4/Tff7b72spanTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"text-[8px] text-gray-400 mt-0.5"Tb4b4b4>
Tff7b72{{ Te6edf3formatTimeTb4b4b4(Te6edf3msgTb4b4b4.Te6edf3timestampTb4b4b4) Tff7b72}}
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>

T8b949e<!-- input -->
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"p-2 bg-white dark:bg-zinc-900 border-t border-gray-200 dark:border-zinc-800"Tb4b4b4>
Tb4b4b4<Tff7b72div Te6edf3classTff7b72=Ta5d6ff"flex gap-1"Tb4b4b4>
Tb4b4b4<Tff7b72input
Te6edf3v-modelTff7b72=Ta5d6ff"Te6edf3newMessageTa5d6ff"
Te6edf3typeTff7b72=Ta5d6ff"text"
Te6edf3classTff7b72=Ta5d6ff"flex-1 bg-gray-50 dark:bg-zinc-800 border border-gray-200 dark:border-zinc-700 rounded-md px-2 py-1 text-xs focus:outline-hidden focus:ring-1 focus:ring-blue-500 text-gray-900 dark:text-zinc-100"
Te6edf3placeholderTff7b72=Ta5d6ff"Type a message..."
Tb4b4b4@Te6edf3keydownTb4b4b4.Te6edf3enterTff7b72=Ta5d6ff"Te6edf3sendMessageTa5d6ff"
Tb4b4b4/Tb4b4b4>
Tb4b4b4<Tff7b72button
Tb4b4b4:Te6edf3disabledTff7b72=Ta5d6ff"Tff7b72!Te6edf3newMessageTb4b4b4.Te6edf3trimTb4b4b4(Tb4b4b4) Tff7b72|| Te6edf3sendingTa5d6ff"
Te6edf3classTff7b72=Ta5d6ff"p-1.5 bg-blue-500 hover:bg-blue-600 disabled:bg-gray-300 dark:disabled:bg-zinc-700 text-white rounded-md transition-colors"
Tb4b4b4@Te6edf3clickTff7b72=Ta5d6ff"Te6edf3sendMessageTa5d6ff"
Tb4b4b4>
Tb4b4b4<Tff7b72v-icon
Tb4b4b4:Te6edf3iconTff7b72=Ta5d6ff"Te6edf3sending Tff7b72? Ta5d6ff'mdi-loading' Tff7b72: Ta5d6ff'mdi-send'Ta5d6ff"
Tb4b4b4:Te6edf3classTff7b72=Ta5d6ff"Tb4b4b4{ Ta5d6ff'animate-spin'Tff7b72: Te6edf3sending Tb4b4b4}Ta5d6ff"
Te6edf3sizeTff7b72=Ta5d6ff"14"
Tb4b4b4>Tb4b4b4<Tb4b4b4/Tff7b72v-iconTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72buttonTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72divTb4b4b4>
Tb4b4b4<Tb4b4b4/Tff7b72templateTb4b4b4>

Tb4b4b4<Tff7b72scriptTb4b4b4>
Tff7b72export Tff7b72default Tb4b4b4{
Te6edf3nameTff7b72: Ta5d6ff"MiniChat"Tb4b4b4,
Te6edf3propsTff7b72: Tb4b4b4{
Te6edf3destinationHashTff7b72: Tb4b4b4{
Te6edf3typeTff7b72: Tffa657StringTb4b4b4,
Te6edf3requiredTff7b72: Tff7b72trueTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3dataTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72return Tb4b4b4{
Te6edf3messagesTff7b72: Tb4b4b4[Tb4b4b4]Tb4b4b4,
Te6edf3newMessageTff7b72: Ta5d6ff""Tb4b4b4,
Te6edf3loadingTff7b72: Tff7b72falseTb4b4b4,
Te6edf3sendingTff7b72: Tff7b72falseTb4b4b4,
Tb4b4b4}Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3watchTff7b72: Tb4b4b4{
Te6edf3destinationHashTff7b72: Tb4b4b4{
Te6edf3immediateTff7b72: Tff7b72trueTb4b4b4,
Te6edf3handlerTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3fetchMessagesTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3mountedTb4b4b4(Tb4b4b4) Tb4b4b4{
T8b949e// Listen for new messages via websocket if possible
T8b949e// For now we'll just poll or rely on parent updates if needed
Tb4b4b4}Tb4b4b4,
Te6edf3methodsTff7b72: Tb4b4b4{
Tff7b72async Te6edf3fetchMessagesTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Tff7b72thisTb4b4b4.Te6edf3destinationHashTb4b4b4) Tff7b72returnTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3loading Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3response Tff7b72= Tff7b72await Tffa657windowTb4b4b4.Te6edf3apiTb4b4b4.Te6edf3getTb4b4b4(
Ta5d6ff`Ta5d6ff/api/v1/lxmf-messages/conversation/Tffd700${Tff7b72thisTb4b4b4.Te6edf3destinationHashTffd700}Ta5d6ff?count=20&order=descTa5d6ff`
Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3messages Tff7b72= Tb4b4b4(Te6edf3responseTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3lxmf_messages Tff7b72|| Tb4b4b4[Tb4b4b4]Tb4b4b4)Tb4b4b4.Te6edf3reverseTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3scrollToBottomTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Te6edf3consoleTb4b4b4.Te6edf3errorTb4b4b4(Ta5d6ff"Failed to fetch messages"Tb4b4b4, Te6edf3eTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72finally Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3loading Tff7b72= Tff7b72falseTb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
Tff7b72async Te6edf3sendMessageTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Tff7b72thisTb4b4b4.Te6edf3newMessageTb4b4b4.Te6edf3trimTb4b4b4(Tb4b4b4) Tff7b72|| Tff7b72thisTb4b4b4.Te6edf3sendingTb4b4b4) Tff7b72returnTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3sending Tff7b72= Tff7b72trueTb4b4b4;
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3response Tff7b72= Tff7b72await Tffa657windowTb4b4b4.Te6edf3apiTb4b4b4.Te6edf3postTb4b4b4(Ta5d6ff"/api/v1/lxmf-messages/send"Tb4b4b4, Tb4b4b4{
Te6edf3lxmf_messageTff7b72: Tb4b4b4{
Te6edf3destination_hashTff7b72: Tff7b72thisTb4b4b4.Te6edf3destinationHashTb4b4b4,
Te6edf3contentTff7b72: Tff7b72thisTb4b4b4.Te6edf3newMessageTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4)Tb4b4b4;

T8b949e// Add message to list locally for immediate feedback
Tff7b72const Te6edf3msg Tff7b72= Te6edf3responseTb4b4b4.Te6edf3dataTb4b4b4.Te6edf3lxmf_messageTb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3messagesTb4b4b4.Te6edf3pushTb4b4b4(Tb4b4b4{
Te6edf3hashTff7b72: Te6edf3msgTb4b4b4.Te6edf3hashTb4b4b4,
Te6edf3contentTff7b72: Te6edf3msgTb4b4b4.Te6edf3contentTb4b4b4,
Te6edf3is_outboundTff7b72: Tff7b72trueTb4b4b4,
Te6edf3timestampTff7b72: Te6edf3msgTb4b4b4.Te6edf3created_atTb4b4b4,
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3newMessage Tff7b72= Ta5d6ff""Tb4b4b4;
Tff7b72thisTb4b4b4.Te6edf3scrollToBottomTb4b4b4(Tb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{
Te6edf3consoleTb4b4b4.Te6edf3errorTb4b4b4(Ta5d6ff"Failed to send message"Tb4b4b4, Te6edf3eTb4b4b4)Tb4b4b4;
Tb4b4b4} Tff7b72finally Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3sending Tff7b72= Tff7b72falseTb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
Te6edf3scrollToBottomTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3$nextTickTb4b4b4(Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72thisTb4b4b4.Te6edf3$refsTb4b4b4.Te6edf3messageListTb4b4b4) Tb4b4b4{
Tff7b72thisTb4b4b4.Te6edf3$refsTb4b4b4.Te6edf3messageListTb4b4b4.Te6edf3scrollTop Tff7b72= Tff7b72thisTb4b4b4.Te6edf3$refsTb4b4b4.Te6edf3messageListTb4b4b4.Te6edf3scrollHeightTb4b4b4;
Tb4b4b4}
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Te6edf3formatTimeTb4b4b4(Te6edf3tsTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3tsTb4b4b4) Tff7b72return Ta5d6ff""Tb4b4b4;
Tff7b72const Te6edf3date Tff7b72= Tff7b72new Tffa657DateTb4b4b4(Te6edf3ts Tff7b72* T79c0ff1000Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Tffa657isNaNTb4b4b4(Te6edf3dateTb4b4b4.Te6edf3getTimeTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4) Tff7b72return Ta5d6ff""Tb4b4b4;
Tff7b72return Te6edf3dateTb4b4b4.Te6edf3toLocaleTimeStringTb4b4b4(Tb4b4b4[Tb4b4b4]Tb4b4b4, Tb4b4b4{ Te6edf3hourTff7b72: Ta5d6ff"2-digit"Tb4b4b4, Te6edf3minuteTff7b72: Ta5d6ff"2-digit" Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4;
Tb4b4b4<Tb4b4b4/Tff7b72scriptTb4b4b4>


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────